package com.jwdemo
{
	import com.jwdemo.GameBitMaps;
	import com.jwdemo.RenderHelper;
	
	import flash.display.BitmapData;
	import flash.display.Graphics;

	public class Enemy implements InfMoveableObject
	{
		private static var canFire:Boolean	=	true ;

		private  var debug:Boolean			=	false ;

		private var position:Vector4		=	new Vector4(0,0,0,0) ;
		private var time:Number				=	0.0 ;

		private var helibodyBM:BitmapData	=	GameBitMaps.GetBitMap("helibody")  ;
		private var helibladesBM:BitmapData	=	GameBitMaps.GetBitMap("heliblades")  ;
		private var helishadowBM:BitmapData	=	GameBitMaps.GetBitMap("helishadow")  ;

		private var paratime:Number 		=	0 ;
		private var cx:Number				=	0 ;
		private var cy:Number				=	0 ;
		private var radius:uint				=	100 ;
		
		private var pRadius:Number			=	600 ;
		private var pK:Number				=	0.15 ;
			
		private var direction:Number 		=	0 ;
		private var aimdirection:Number 	=	0 ;
		private var phase:Number			=	Math.random()*6.28  ;
		private var firephase:Number		=	Math.random()*6.28  ;

		private var centreduration:Number	=	60 ;
		private var centreamp:Number		=	600 ;
		private var tSpeed:Number			=	1 ;
		
		private var canfire:Boolean ;

		private var fired:uint ;
		private var fireperiod:Number ;
		private var lastfired:Number ;
		private var lastx:Number ;
		private var lasty:Number ;
		
		private var fireFunction:Function =	function(fired:int):Object { return { x: 0 , y: 0, z: 0 } ; } ;

		private var firingpos:Vector4 ;

		static public var FiringOffsetData:Object = 
			{
				enemyheli:		function(fired:int):Object { return (fired % 2) ? {x:10, y:-8, z:0} : {x:-10, y:-8, z:0}; },
				playerheli:		function(fired:int):Object { return (fired % 2) ? {x:10, y:-8, z:0} : {x:-10, y:-8, z:0}; },
				largejeep:		function(fired:int):Object { return (fired % 2) ? {x:10, y:-16, z:0} : {x:-14, y:-16, z:0}; },
				smalljeep:		function(fired:int):Object { return  {x:0, y:-20, z:0} ; },
				tank:			function(fired:int):Object { return {x:0, y:-52, z:0} ; }
			} ;
		

		static public function pickRandomPhase():Number
		{
			return Math.random()*6.28 ;	
		} 
		
		//TODO - finish off - probably only needs properties.
		
		public function Enemy(position:Vector4,phase:Number = 0, tspeed:Number = 1)
		{
			this.position 		=	new Vector4(position.X(), position.Y(), position.Z(), position.W()) ;
			this.cx				=	this.position.X() ;
			this.cy				=	this.position.Y() ;
			this.lastx			=	this.position.X();
			this.lasty			=	this.position.Y();
			this.firingpos		=	new Vector4(0,0);

			this.tSpeed			=	tspeed ;
			this.phase			=	phase ;
			this.firephase		=	Math.random()*6.28 ;
			
			this.radius			=	100 ;
			this.canfire		=	true ;
			this.lastfired		=	0 ;
			this.fireperiod		=	0.125 ;
			this.fired			=	0 ;
			
			this.fireFunction	=	FiringOffsetData.enemyheli ;
			
			this.update(0) ;	// Work out 1st position in our orbit
		}

		public static function Create(properties:Object):Enemy
		{
			// TODO
			return null ;	
		}
		
		public function isAlive():Boolean
		{
			return true;
		}

		public function setPosition(xpos:Number,ypos:Number):void
		{
			this.position.SetXyzw(xpos,ypos) ;
		}

		public function getPosition():Object
		{
			return { _x: position.X(), _y: position.Y() };
		}
		
		public function getVectorPosition():Vector4
		{
			return position;
		}
		public function update(dt:Number):void
		{
			time	=	time	+	dt ;
			updateFlying(dt) ;
			attemptFire(dt) ;

		}

		private function GetFiringDirection():Number
		{
			// TODO
			// Calculate firing position - considering the parts 
			// which make up our Enemy object.
			
//			for (var idx in this.parts)
//			{
//				var part = this.parts[idx]
//				if (part.ctype=='turret') 
//				{
//					return part.GetFiringDirection() ;
//				}
	//		}
			return this.direction ;
			
		}
		
		public function getFiringOffset(frd:int):Object
		{
			return this.fireFunction != null ? this.fireFunction(frd  < 0 ? this.fired : frd ) :  {x:0, y:0, z:0} ;
		}

		
		private function getFiringPosition(fired:uint,angle:Number) : Vector4 
		{
			var rangle:Number	=	angle || 0 ;
			var	cos:Number		=	Math.cos(rangle*Math.PI/180) ;
			var sin:Number		=	Math.sin(rangle*Math.PI/180) ;
			
		
			var x:Number		=	this.position.X(), y:Number	=	this.position.Y(), z:Number	=	this.position.Z() ;
		
			var fo:Object		=	this.getFiringOffset(fired) ;
			var ox:Number		=	fo.x, oy:Number	= fo.y ;
			
			var	tox:Number		=	ox*cos - oy*sin ;
			var	toy:Number		=	ox*sin + oy*cos ;
			
			this.firingpos.SetXyzw(x + tox, y + toy, z, 0) ;
			return this.firingpos ;
		}
		

		
		// Flying object - without a path - follow a 
		// simple figure of '8' .
		
		private function updateFlying(dt:Number) : void
		{
			calcDirection() ;
			this.paratime 			= 	this.paratime + dt*(this.tSpeed) ;
			var k:Number			=	this.pK ;

			this.aimdirection 		=	this.direction ;

			var ptime:Number		=	k*this.paratime + this.phase;
			var radius:Number 		=	this.pRadius ;

			// move centre point - around a circle			
			var amp:Number			=	this.centreamp ;
			var centreFreq:Number	=	6/this.centreduration;
			var	cx:Number			=	this.cx	+ amp*Math.cos(ptime*centreFreq) ;
			var	cy:Number			=	this.cy	+ amp*Math.sin(ptime*centreFreq) ;
			
			
			// TODO - use new centre point - replace this.cx, this.cy for cx,cy 
			
			var ypos:Number			=	(this.cx + (radius+Math.cos(2*ptime))*Math.cos(3*ptime)) ;
			var xpos:Number			=	(this.cy + (radius+Math.cos(2*ptime))*Math.sin(5*ptime)) ;

			this.setPosition((xpos),(ypos))

		}
		
		
		private function calcDirection(): void
		{
			
			// Look in the direction we are moving
			var xpos:Number		=	position.X(), ypos:Number	 =  position.Y() ;
			
			var dx:Number 			=	xpos - lastx ;
			var dy:Number			= 	ypos - lasty ;
			var th:Number 			= 	Math.atan2(dy,dx)  
									
			this.direction	=	(th*180/Math.PI) + 90
			this.lastx		=	xpos
			this.lasty		=	ypos
			
		}
		

		public function attemptFire(dt:Number, viewdist:Number = 0) : void
		{
				
				// Attempt to fire Homing Missile
				
//				if (Enemy.canfire && MissileManager.CanFire() && this.missilerate && this.time - (this.lastmissile || 0) > this.missileperiod && this.targetlength < 600 && this.aimtol < AIMTOL)
//				{
//					var fDirection		=	this.GetFiringDirection() ;
//					MissileManager.AddMissile( this, this.GetFiringPosition(this.fired,fDirection),fDirection - 90,this.follow,1,15) ; 
					
//					this.lastmissile	=	this.time ;
//					this.fired++ ;
//				}
				
				// Attempt to fire bullets
				if (Enemy.canFire && this.canfire && 
					this.time - this.lastfired  > this.fireperiod && 
					Math.sin(6*this.time/8+this.firephase) > 0 && 
					Math.sin(6*this.time/4+this.firephase) > 0) 
				{
					
					
					//BulletManager.Fire				=	function(owner,damage,vel,angle,duration,animation,scale,radius)
					
					// TODO Define thse as constants
					
					var kDAMAGE:Number		=	10 ;
					var kDURATION:Number	=	0.75 ;
					var kVELOCITY:Number 	=	600 ;	// should be 600
					
					var animation:TextureAnim = new SpriteSheet(GameBitMaps.GetBitMap("bullets"),4,32).createTextureAnimation(12) ;
					GameObjectManager.Fire(this,kDAMAGE,kVELOCITY,this.GetFiringDirection(),kDURATION,animation,1,10) ;
					
					this.fired++ ;
					this.lastfired	=	this.time
				}
			
		}
		
		public function render(rHelper:RenderHelper):void 
		{

			var xpos:Number		=	this.position.X() 
			var ypos:Number 	= 	this.position.Y();
			
			rHelper.drawImage(helishadowBM,xpos-16,ypos+16,0.75,0.75,direction) ;
			rHelper.drawImage(helibodyBM,xpos,ypos,0.75,0.75,direction) ;
			rHelper.drawImage(helibladesBM,xpos,ypos,0.75,0.75,time*600) ;
			//rHelper.drawCircle(xpos,ypos,120,0xFF0000) ;
		
	
			// Debug draw firing holes.		
			
			if (this.debug && this.time - this.lastfired < 1) 
			{
				var ang:Number	=		this.GetFiringDirection() ;
				rHelper.drawCircle(this.getFiringPosition(0,ang).X(),this.getFiringPosition(0,ang).Y(),2,0xFF0000) ;
				rHelper.drawCircle(this.getFiringPosition(1,ang).X(),this.getFiringPosition(1,ang).Y(),2,0xFF0000) ;
				rHelper.drawText(""+int(xpos)+","+int(ypos),xpos,ypos+20) ;

				//	rHelper.drawCircle(xpos,ypos,4,0xFF0000) ;
			}
			

		}

		
	}

}